! TIME
! 
!   This module contains functions to compute timings of algorithms.
!   Both wallclock time and processor time are supported.
!
!   Because of the way the wallclock_tic and wallclock_toc values are
!   computed, there are some restrictions for the wallclock-time measurements:
!   * Maximum measurable time is 1 month.
!   * Beginning and end of computation must be within the same month.
! 
! HISTORY
! 
!   20110317 KP - Updated documentation, changed to functions
!   2009.... BV - Initial version
! 
! AUTHOR
! 
!   Koen Poppe, Department of Computer Science,
!   Katholieke Universiteit Leuven, Celestijnenlaan 200A,
!   B-3001 Heverlee, Belgium
!   Email:  Koen.Poppe@cs.kuleuven.be
!
!   Bart Vandewoestyne, Dept. of Mathematics,
!   Katholieke Universiteit Leuven (Kortrijk), Etienne Sabbelaan 53,
!   B-8500 Kortrijk, Belgium
!   Email:  Bart.Vandewoestyne@kuleuven-kortrijk.be
!
module time
    implicit none
    private
    save

    !--------------------------------------------------------------------------
    ! Wallclock
    !--------------------------------------------------------------------------

    public :: wallclock_tic
    public :: wallclock_toc

    integer, parameter, public :: clock_kind = selected_int_kind(10)
    ! NOTE: maximum value of integer(kind=clock_kind) is 10^10, this is more
    !       than the 31 days 23 hours 59 minutes 60 seconds 999 milliseconds
    !       (=2 764 800 999 ms) allowed by the restrictions in the prologue.
    integer(kind=clock_kind) :: wallclock_start
    
    !--------------------------------------------------------------------------
    ! Processor time
    !--------------------------------------------------------------------------

    public :: processor_tic
    public :: processor_toc

    real :: processor_start_time

contains

    !--------------------------------------------------------------------------
    ! Wallclock
    !--------------------------------------------------------------------------
    
    ! Initialize the wallclock-timer.
    subroutine wallclock_tic()
        wallclock_start = date_and_time_in_ms()
    end subroutine wallclock_tic
    
    ! Return the number of milliseconds since the last wallclock_tic.
    function wallclock_toc() result( ms )
        integer(kind=clock_kind) :: ms
        ms  = (date_and_time_in_ms() - wallclock_start)
    end function wallclock_toc
    
    ! Current date and time in milliseconds.
    function date_and_time_in_ms() result( ms )
        integer(kind=clock_kind) :: ms
        
        integer, dimension(8) :: dNt
        call date_and_time(values=dNt)
        
        ms = dNt(8) + 1000*(dNt(7) + 60*(dNt(6) + 60*(dNt(5) + 24*dNt(3))))
            
    end function date_and_time_in_ms
    
    !--------------------------------------------------------------------------
    ! Processor time
    !--------------------------------------------------------------------------
    
    ! Initialize the processor-time based timer.
    subroutine processor_tic()
      call cpu_time(processor_start_time)
    end subroutine processor_tic

    ! Return the processor time since the last processor_tic()
    function processor_toc() result( sec )
        real :: sec
        real :: processor_stop_time
        
        call cpu_time(processor_stop_time)
        
        sec = (processor_stop_time - processor_start_time) 
        
    end function processor_toc

end module time
